package com.gopay.bis.bos.ebank.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.naming.CommunicationException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 使用httpClient形式发送报文
 * 
 * @BosHttpTransport.java
 * @author lilili
 */
@SuppressWarnings("unchecked")
public class BosHttpTransport {
	 private static Logger logger = LoggerFactory.getLogger(BosHttpTransport.class);

	    private String url;
	    /**
	     * timeout.
	     */
	    private int timeout = 6000;
	    /**
	     * encoding
	     */
	    private String sendEncoding = "UTF-8";
	    /**
	     * retryConnTimes.
	     */
	    private int retryConnTimes = 5;
	   

	    /**
	     * HTTP请求
	     * 
	     * @param obj
	     * @return
	     * @throws CommunicationException
	     */
	    public String submit(Object obj) throws CommunicationException {
	    	
	    	SSLSocketFactory sf=null;
			if (url.startsWith("https:")) {
				sf=setSSL(url);
			}

	    	CloseableHttpClient httpClient = HttpClients.custom()
	    			.setRetryHandler(new DefaultHttpRequestRetryHandler(retryConnTimes, false))
	    			.setSSLSocketFactory(sf)
	    			.build();
	    	
	    	
	    	HttpPost method = new HttpPost(url);
	    	
	    	RequestConfig requestConfig = RequestConfig.custom()
	    			.setSocketTimeout(timeout)
	    			.setConnectTimeout(timeout)
	    			.setConnectionRequestTimeout(timeout)
	    			.build();
	        if (StringUtils.isNotEmpty(this.sendEncoding)) {
	            method.setHeader(HTTP.CONTENT_ENCODING, sendEncoding);
	        }
	        method.setHeader(HTTP.USER_AGENT, "Rich Powered/1.0");
	        
	        method.setConfig(requestConfig);

	        if (obj != null) {
	            if (obj instanceof Map) {
	                Map<String, String> paraMap = (Map<String, String>) obj;
	                List<NameValuePair> nvps = new ArrayList<NameValuePair>();
	                
	                for (Iterator<String> iter = paraMap.keySet().iterator(); iter.hasNext();) {
	                    String key = iter.next();
	                    String value = "";
	                    if (paraMap.get(key) != null) {
	                        value = paraMap.get(key);
	                    }

	                    nvps.add(new BasicNameValuePair(key, value));
	                }
	                
	                try {
	                	if (StringUtils.isNotEmpty(this.sendEncoding))
	                		method.setEntity(new UrlEncodedFormEntity(nvps, sendEncoding));
	                	else
	                		method.setEntity(new UrlEncodedFormEntity(nvps));
					} catch (UnsupportedEncodingException e) {
						if (logger.isErrorEnabled()) {
			                logger.error("Fatal transport error while try connect to [" + url + "]");
			                logger.error("Cause: " + e.getMessage());
			            }
						e.printStackTrace();
					}
	            } else if (obj instanceof byte[]) {
	                method.setEntity(new ByteArrayEntity((byte[]) obj));
	                if (logger.isInfoEnabled()) {
	                    logger.info("Sent Data: \n" + new String((byte[]) obj));
	                }
	            } else {
	                throw new IllegalArgumentException("submit(Object obj): obj should be Map or byte[]");
	            }
	        }

	        int statusCode = 0;
	        String result = "";
	        CloseableHttpResponse  response =null;
	        try {
	        	response = httpClient.execute(method);
	            statusCode = response.getStatusLine().getStatusCode();
	            HttpEntity responseEntity = response.getEntity();
	            result = EntityUtils.toString(responseEntity, sendEncoding);
	            if (logger.isInfoEnabled()) {
	                logger.info("Received Data: \n" + result);
	            }
	        } catch (IOException e) {
	            if (logger.isErrorEnabled()) {
	                logger.error("Fatal transport error while try connect to [" + url + "]");
	                logger.error("Cause: " + e.getMessage());
	            }
	            e.printStackTrace();
	        } finally {
	            if (response != null) {
	            	try {
						response.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
	            }
	        }
	        if (statusCode != HttpStatus.SC_OK) {
	            if (logger.isErrorEnabled()) {
	                logger.error("Answer from [" + url + "] status code: [" + statusCode + "]");
	            }
	            throw new CommunicationException(String.valueOf(statusCode));
	        }

	        return result;
	    }
	    
	    private static SSLSocketFactory setSSL(String strUrl) {
			try {
				URL url = new URL(strUrl);
				String host = url.getHost();
				int port = url.getPort();
				if (port <= 0) {
					port = 443;
				}
				X509TrustManager xtm = new X509TrustManager() {
					public void checkClientTrusted(X509Certificate[] chain,
							String authType) throws CertificateException {
					}
					public void checkServerTrusted(X509Certificate[] chain,
							String authType) throws CertificateException {
					}
					public X509Certificate[] getAcceptedIssuers() {
						return new X509Certificate[] {};
					}
				};
				SSLContext ctx = SSLContext.getInstance("SSL");
				// 使用TrustManager来初始化该上下文，TrustManager只是被SSL的Socket所使用
				ctx.init(null, new TrustManager[] { xtm }, null);
				SSLSocketFactory sf = new SSLSocketFactory(ctx,
						SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
				return sf;
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}


	    public void setUrl(String url) {
	        this.url = url;
	    }

	    public void setTimeout(int timeout) {
	        this.timeout = timeout;
	    }

	    public void setSendEncoding(String sendEncoding) {
	        this.sendEncoding = sendEncoding;
	    }

	    public void setRetryConnTimes(int retryConnTimes) {
	        this.retryConnTimes = retryConnTimes;
	    }
	

}
